﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Licensed MIT: http://www.opensource.org/licenses/mit-license.php

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System;
//using System.Linq.Expressions;
using System.Linq.Dynamic;

namespace DNA.Mvc.Community.Data.Entity
{
    public class ForumRepository : GenericForumRepository<Forum>, IForumRepository
    {
        public ForumRepository() : base() { }

        public ForumRepository(ForumDb context) : base(context) { }

        public bool HasChildren(int id)
        {
            return DbSet.Count(f => f.ParentID == id) > 0;
        }

        public IEnumerable<Forum> GetForums(int parentID = 0)
        {
            return Filter(f => f.ParentID == parentID).OrderBy(f => f.Pos);
        }

        /// <summary>
        /// Get the threads for specified forum id.
        /// </summary>
        /// <param name="forumID">Specified the forum id.</param>
        /// <param name="pageIndex">Speicifed the page index</param>
        /// <param name="pageSize">Specified the page size</param>
        /// <param name="totalRecords">Specified the return total records count</param>
        /// <returns>The thread colleciton.</returns>
        public IEnumerable<Thread> GetThreads(int forumID, string sortby, SortingOrders order, int pageIndex, int pageSize, out int totalRecords)
        {
            var skips = pageIndex * pageSize;
            totalRecords = Context.Set<Thread>().Count(t => t.ForumID == forumID && t.IsApproved);

            var query = Context.Set<Thread>().Where(t => t.ForumID == forumID && t.IsApproved);

            if (string.IsNullOrEmpty(sortby))
                query = query.OrderByDescending(t => t.IsPinned)
                .ThenByDescending(t => t.Posted)
                .ThenByDescending(t => t.TotalReads)
                .ThenByDescending(t => t.TotalPosts);
            else
            {
                if (order == SortingOrders.Asc)
                    query = query.OrderBy(sortby);
                else
                    query = query.OrderBy(sortby+" desc");
            }

            if (skips > 0)
                return query.Skip(skips).Take(pageSize);
            else
                return query.Take(pageSize);
        }

        public void Move(int parentID, int id, int pos)
        {
            var forum = Find(id);

            if (forum == null)
                throw new Exception(string.Format("Forum {0} not found",id));
            var seqCollection = DbSet.Where(p => p.ParentID == parentID)
                                                .OrderBy(p => p.Pos)
                                                .Select(p => p.Pos);

            if (seqCollection.Count() == 0)
            {
                forum.Pos = 0;
                forum.ParentID = parentID;
                if (IsOwnContext)
                    Context.SaveChanges();
                return;
            }

            int upperBound = seqCollection.Max();
            int lowerBound = seqCollection.Min();

            int _from = forum.Pos;
            int _to = pos;

            if (_to > upperBound)
                _to = upperBound;
            else
            {
                if (_to < lowerBound)
                    _to = lowerBound;
            }

            //1.Move up
            if (_from > _to)
            {
                DbSet.Where(p => p.ParentID == parentID && p.Pos >= _to && p.Pos < _from)
                    .OrderBy(p => pos)
                    .AsParallel()
                    .ForAll(p => p.Pos++);

            }

            //2.Move down
            if (_from < _to)
            {
                DbSet.Where(p => p.ParentID == parentID && p.Pos > _from && p.Pos <= _to)
                   .OrderBy(p => pos)
                   .AsParallel()
                   .ForAll(p => p.Pos--);
            }

            forum.Pos = _to;
            forum.ParentID = parentID;

            if (IsOwnContext) Context.SaveChanges();
        }

        public int GetTotalModeratedThreadsCount(int forumID)
        {
            var unappovedThreads = Context.Set<Thread>().Count(t => !t.IsApproved);
            var unappovedPostThreads = Context.Set<Post>().Where(p => !p.IsApproved && !p.IsThread)
                                                                    .Select(p => p.ThreadID)
                                                                    .Distinct()
                                                                    .Count();
            return unappovedPostThreads + unappovedThreads;
        }

        public int GetTotalModeratedPostsCount(int forumID)
        {
            return Context.Set<Post>().Where(p => !p.IsApproved).Where(p => !p.IsThread).Count();
        }

        public IEnumerable<Forum> GetModeratedForums(string userName)
        {
            return DbSet.Where(f => f.IsModerated && (!f.IsGroup) && Context.Set<Moderator>().Where(m => m.UserName == userName).Select(m => m.ForumID).Contains(f.ID));
        }
    }
}
